package com.rescue.aspect;

import com.alibaba.fastjson.JSON;
import com.rescue.annotation.GlobalInterceptor;
import com.rescue.constant.*;
import com.rescue.context.BaseContext;
import com.rescue.enumeration.OperationFrequencyType;
import com.rescue.exception.BaseException;
import com.rescue.forum.syssetting.CommentSet;
import com.rescue.forum.syssetting.LikeSet;
import com.rescue.forum.syssetting.PostSet;
import com.rescue.mapper.LikeRecordMapper;
import com.rescue.mapper.SysSettingMapper;
import com.rescue.result.Result;
import com.rescue.service.ArticleService;
import com.rescue.service.CommentService;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import java.lang.reflect.Method;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Objects;

/**
 * 自定义切面，实现公共字段自动填充处理逻辑
 */
@Aspect
@Slf4j
@Component
public class OperationAspect {
    @Autowired
    private ArticleService articleService;
    @Autowired
    private SysSettingMapper sysSettingMapper;
    @Autowired
    private CommentService commentService;
    @Autowired
    private LikeRecordMapper likeRecordMapper;

    @Pointcut("execution(* com.rescue.controller.user.*.*(..)) && @annotation(com.rescue.annotation.GlobalInterceptor)")
    public void requestInterceptor() {
    }


    @Around("requestInterceptor()")
    public Object interceptorDo(ProceedingJoinPoint point){
        try {
            Object target = point.getTarget();
            Object[] args = point.getArgs();
            String methodName = point.getSignature().getName();
            Class<?>[] parameterTypes = ((MethodSignature) point.getSignature()).getMethod().getParameterTypes();

            Method method = null;

            method = target.getClass().getMethod(methodName, parameterTypes);

            GlobalInterceptor interceptor = method.getAnnotation(GlobalInterceptor.class);
            if (null == interceptor) {
                return null;
            }
            /**
             * 效验频次
             */
            this.checkFrequency(interceptor.frequency());
            Object proceed = point.proceed();
            if (proceed instanceof Result) {
                Result result = (Result) proceed;
                if (Objects.equals(result.getCode(), StatusConstant.ENABLE)) {
                    this.addOpCount(interceptor.frequency());
                }
            }
            return proceed;
        } catch (BaseException e) {
            throw e;
        } catch (Exception e) {
            throw new BaseException(MessageConstant.SERVER_ERROR);
        } catch (Throwable e) {
            throw new BaseException(MessageConstant.SERVER_ERROR);
        }
    }

    private void addOpCount(OperationFrequencyType type) {
        if (type == null || type == OperationFrequencyType.NO_CHECK) {
            return;
        }
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
        HttpSession session = request.getSession();
        LocalDateTime localDateTime = LocalDateTime.now();
        String curDate = localDateTime.format(DateTimeFormatter.ofPattern(DateTimePatternConstant.YYYY_MM_DD));
        //记录特定操作的类型
        String sessionKey = WebConstant.SESSION_KEY_FREQUENCY + curDate + type.getOperType() + BaseContext.getCurrentId();
        Integer count = (Integer) session.getAttribute(sessionKey);
        count = count==null?0:count;
        session.setAttribute(sessionKey, count + 1);
    }

    private void checkFrequency(OperationFrequencyType type) throws Exception {
        if (type == null || type == OperationFrequencyType.NO_CHECK) {
            return;
        }
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
        HttpSession session = request.getSession();
        LocalDateTime localDateTime = LocalDateTime.now();
        String curDate = localDateTime.format(DateTimeFormatter.ofPattern(DateTimePatternConstant.YYYY_MM_DD));
        //记录特定操作的类型
        String sessionKey = WebConstant.SESSION_KEY_FREQUENCY + curDate + type.getOperType() + BaseContext.getCurrentId();
        Integer count = (Integer) session.getAttribute(sessionKey);
        switch (type) {
            case POST_ARTICLE:
                if (count == null) {
                    count = articleService.getArticleCount(localDateTime);
                }
                //获取每日可发文章数
                String set = sysSettingMapper.getByCode(SysSettingConstant.POST_SETTING);
                PostSet postSet = JSON.parseObject(set, PostSet.class);
                if (count >= postSet.getPostDayCountThreshold()) {
                    throw new BaseException(MessageConstant.THE_NUMBER_OF_POSTS_HAS_REACHED_THE_DAILY_LIMIT);
                }
                break;
            case POST_COMMENT:

                if (count == null) {
                    count = commentService.getCommentCount(localDateTime);
                }
                //获取每日可发评论数
                String setC = sysSettingMapper.getByCode(SysSettingConstant.COMMENT_SETTING);
                CommentSet commentSet = JSON.parseObject(setC, CommentSet.class);
                if (count >= commentSet.getCommentDayCountThreshold()) {
                    throw new BaseException(MessageConstant.THE_NUMBER_OF_POSTS_HAS_REACHED_THE_DAILY_LIMIT);
                }
                break;
            case DO_LIKE:
                // 频次校验
                if (count == null) {
                    count = likeRecordMapper.getLikeCount(localDateTime.toLocalDate(), BaseContext.getCurrentId());
                }
                //获取每日可点赞数
                String setL = sysSettingMapper.getByCode(SysSettingConstant.LIKE_SETTING);
                LikeSet likeSet = JSON.parseObject(setL, LikeSet.class);
                if (count >= likeSet.getLikeDayCountThreshold()) {
                    throw new BaseException(MessageConstant.THE_NUMBER_OF_POSTS_HAS_REACHED_THE_DAILY_LIMIT);
                }
                break;
        }
    }
}
